use std::sync::mpsc;
use std::thread;

use super::Message;
use crate::appender::Appender;
use crate::TargetIndex;

pub fn init() -> crate::Result<(thread::JoinHandle<()>, mpsc::Sender<Message>)> {
    let (sender, receiver) = mpsc::channel();
    let th = thread::Builder::new()
        .name("logger".to_string())
        .spawn(move || thread_fun(receiver))?;
    Ok((th, sender))
}

#[derive(Default)]
struct Target {
    appenders: Vec<Appender>,
}

fn thread_fun(receiver: mpsc::Receiver<Message>) {
    let mut targets: [Target; TargetIndex::Max as usize + 1] = Default::default();

    for message in receiver {
        match message {
            Message::Record(record) => {
                for appender in targets[record.target()].appenders.iter_mut() {
                    if let Err(e) = appender.process(&record) {
                        println!("log process error: {} record: {}", e, record);
                    }
                }
            }
            Message::AppenderAdd((target, appender)) => {
                let appenders = &mut targets[target as usize].appenders;
                if !(appender.name() == "console_appender" && appenders.contains(&appender)) {
                    appenders.push(appender);
                }
            }
            Message::AppenderRemove((target, appender)) => {
                targets[target as usize]
                    .appenders
                    .retain(|ref x| x.name() != appender);
            }
            Message::Terminate => {
                break;
            }
        }
    }
}
